package com.tengju.bff.interfaces.manage.crm.activity.facade;

import com.beust.jcommander.internal.Lists;
import com.tengju.bff.interfaces.manage.crm.activity.facade.assembler.ActivityAssembler;
import com.tengju.bff.interfaces.manage.crm.activity.facade.assembler.QueryAssembler;
import com.tengju.bff.interfaces.manage.crm.activity.form.*;
import com.tengju.bff.interfaces.manage.crm.activity.vo.ActivityCalendarVO;
import com.tengju.bff.interfaces.manage.crm.activity.vo.ActivityDetailResVO;
import com.tengju.bff.interfaces.manage.crm.activity.vo.ActivityTargetValueVO;
import com.tengju.bff.interfaces.manage.crm.dealer.assembler.CrmDealerVOAssembler;
import com.tengju.bff.interfaces.manage.crm.dealer.vo.DealerSupInfoVO;
import com.tengju.bff.interfaces.manage.crm.user.vo.NicknameVO;
import com.tengju.bff.interfaces.shared.Formatter;
import com.tengju.bff.interfaces.shared.*;
import com.tengju.bff.interfaces.shared.render.KVAssembler;
import com.tengju.bff.interfaces.shared.render.MetaUtil;
import com.tengju.bff.interfaces.shared.servlet.ServletContextUtil;
import com.tengju.data.domain.model.activity.KanbanType;
import com.tengju.data.domain.model.analysis.Meta;
import com.tengju.data.domain.model.analysis.MetaHolder;
import com.tengju.data.domain.model.analysis.Row;
import com.tengju.data.domain.model.clickhouse.crm.CrmActivityAnalysisRepository;
import com.tengju.data.domain.model.cqrs.CrmActivityAnalysisQO;
import com.tengju.data.domain.model.cqrs.CrmActivityCompleteValueQO;
import com.tengju.data.domain.model.user.StarLevelEnum;
import com.tengju.data.domain.shared.DateUtil;
import com.tengju.data.domain.shared.Month;
import com.tengju.motivation.domain.model.activity.*;
import com.tengju.user.application.shared.ApplicationException;
import com.tengju.user.application.user.UserDocumentService;
import com.tengju.user.application.user.dto.UserSearchForm;
import com.tengju.user.domain.model.chief.ChiefGenSecRelation;
import com.tengju.user.domain.model.chief.ChiefGenSecRelationRepository;
import com.tengju.user.domain.model.csm.dealer.CrmDealerInfo;
import com.tengju.user.domain.model.csm.dealer.CrmDealerInfoRepository;
import com.tengju.user.domain.model.department.DepartmentId;
import com.tengju.user.domain.model.doc.UserDocument;
import com.tengju.user.domain.model.user.UserIdCode;
import com.tengju.user.domain.model.user.UserInfo;
import com.tengju.user.domain.model.user.UserInfoRepository;
import com.tengju.user.domain.service.RemoteUserService;
import com.tengju.user.domain.shared.BizException;
import com.tengju.user.domain.shared.CastUtil;
import io.netty.util.concurrent.CompleteFuture;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.validation.Valid;
import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
@RequiredArgsConstructor(onConstructor_ = {@Autowired})
@Slf4j
public class ActivityTargetAnalysisFacade {

    private final MetaHolder metaHolder;
    private final CrmActivityAnalysisRepository crmActivityAnalysisRepository;
    private final UserInfoRepository userInfoRepository;
    private final ActivityRepository activityRepository;
    private final ChiefGenSecRelationRepository chiefGenSecRelationRepository;
    private final UserDocumentService userDocumentService;
    private final CrmDealerInfoRepository crmDealerInfoRepository;
    private final RemoteUserService remoteUserService;


    @Value("${sso.department.tree.filter.departmentId}")
    private String filterDepartmentIds;


    @Value("#{${sso.department.leader}}")
    Map<Long, Long> departmentLeader;


    public List<KVVO<String, Integer>> getKanbanTypes() {
        return Arrays.stream(KanbanType.values())
                .map(kanbanType -> KVVO.of(kanbanType.getDesc(), kanbanType.getVal()))
                .collect(Collectors.toList());
    }


    private List<List<ActivityDetailResVO>> buildXySchedule(List<ActivityDetailResVO> sortActivity, LocalDate startDate, LocalDate endDate) {

        List<List<ActivityDetailResVO>> xAxis = Lists.newArrayList();
        while (sortActivity.size() > 0) {
            LocalDate timeNode = LocalDate.MIN;
            List<ActivityDetailResVO> yAxis = Lists.newArrayList();

            Iterator<ActivityDetailResVO> iterator = sortActivity.iterator();
            while (iterator.hasNext()) {
                ActivityDetailResVO activityNode = iterator.next();
                if (activityNode.getStartTime().isAfter(timeNode)) {
                    //活动时间周期与查询的月 取交集
                    activityNode.subPeriodWithMonth(startDate, endDate);
                    if (activityNode.getStartTime() == null || activityNode.getEndTime() == null) {
                        iterator.remove();
                        continue;
                    }
                    yAxis.add(activityNode);
                    iterator.remove();
                    timeNode = activityNode.getEndTime();
                }
            }
            xAxis.add(yAxis);
        }
        return xAxis;
    }

    public ActivityCalendarVO getActivityCalendar(ActivityCalendarQuery query) {
        List<KVVO<String, String>> dateTimeBox = new ArrayList<>();
        Month month = new Month(query.getMonthInt());
        // TJ 侧的有效活动配置
        List<Long> validActivityIds = activityRepository.listValidTimeActivityIds(month.getStartDate(), month.getEndDate());
        List<ActivityId> activityIdList = validActivityIds.stream().map(ActivityId::new).collect(Collectors.toList());
        List<Activity> activityList = activityRepository.getActivityById(activityIdList);
        //过滤出有效活动并且进行转换（按活动开始时间升序排序）
        List<ActivityDetailResVO> sortActivity = activityList.stream()
                .map(ActivityAssembler::assemblerToVO)
                .filter(Objects::nonNull)
                .sorted(Comparator.comparing(ActivityDetailResVO::getStartTime)).collect(Collectors.toList());
        // 构建返回的日历列表
        List<List<ActivityDetailResVO>> schedule = buildXySchedule(sortActivity, month.getStartDate(), month.getEndDate());
        LocalDate start = month.getStartDate();
        while (start.isBefore(month.nextMonth().getStartDate())) {
            dateTimeBox.add(KVVO.of(DateUtil.formatLocalDate(start), start.toString()));
            start = start.plusDays(1L);
        }
        return new ActivityCalendarVO(dateTimeBox, schedule);

    }


    public ActivityTargetValueVO getActivityCalendarTarget(ActivityCalendarTargetQuery query) {
        List<Long> genSecIdCodeList = ServletContextUtil.getServletContext().getGenSecIdCodes()
                .stream().map(UserIdCode::getValue).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(genSecIdCodeList)){
            throw new InterfaceException(InterfaceCode.INSUFFICIENT_AUTHORITY);
        }
        List<Row> rows = crmActivityAnalysisRepository
                .activityCompleteTotal(new CrmActivityCompleteValueQO(query.getActivityId(), query.getKanbanType(), query.getActivityType(), genSecIdCodeList));
        if (CollectionUtils.isEmpty(rows) | rows.get(0) == null) {
            return new ActivityTargetValueVO("-", "-", "-");
        }
        Row res = rows.get(0);
        String completeVal = res.getValue("complete_val").toString();
        String targetVal = res.getValue("target_val").toString();
        String completePercent = Formatter.calRate(completeVal, targetVal);
        return new ActivityTargetValueVO(String.valueOf(new AmountVO(AmountType.NUMBER_2, targetVal)),
                String.valueOf(new AmountVO(AmountType.NUMBER_2, completeVal)), completePercent);

    }


    public List<KVVO<String, Long>> subjectList(@Valid ActivityBaseQuery query) {
        List<KVVO<String, Long>> result = new ArrayList<>();
        result.add(KVVO.of("全部", -2L));
        Activity activity = activityRepository.getActivityById(new ActivityId(query.getActivityId()));
        if (activity == null) {
            return result;
        }
        List<Row> rows = crmActivityAnalysisRepository.subjectNameList(query.getActivityId(), activity.getExtraInfo().getActivityType().getVal());
        List<KVVO<String, Long>> collect = rows.stream()
                .map(v -> KVVO.of(String.valueOf(v.getValue("subject_name")),
                        Long.parseLong(String.valueOf(v.getValue("subject_id"))))).collect(Collectors.toList());
        result.addAll(collect);
        return result;
    }


    public TableVO dealerTargetReachTable(ActivityTeamQuery query) {
        TableVO table = new TableVO();
        Map<String, Meta> metaMap = metaHolder.listMeta("crm_activity_detail_dealer_table");
        TableAssembler.buildColumns(table, metaMap.values());
        CrmActivityAnalysisQO qo = buildQueryDTO(query, metaMap);
//        List<Row> rows = crmActivityAnalysisRepository.dealerTargetReachTable(qo);
//        int total = crmActivityAnalysisRepository.countDealerTargetReachTable(qo);


        CompletableFuture<List<Row>> rowCompletableFuture = CompletableFuture.supplyAsync(() -> {
            return crmActivityAnalysisRepository.dealerTargetReachTable(qo);
        });
        CompletableFuture<Integer> totalCompletableFuture = CompletableFuture.supplyAsync(() -> {
            return crmActivityAnalysisRepository.countDealerTargetReachTable(qo);
        });
        List<Row> rows = null;
        int total = 0;
        try {
            rows = rowCompletableFuture.get();
            total = totalCompletableFuture.get();
        } catch (Exception e) {
            log.info("经销商达成查询异常！",e);
            throw new RuntimeException("经销商达成查询异常！",e);
        }
        Map<Long, ChiefGenSecRelation> chiefMap = getChiefMap(rows, "bl_sec_id_code");
        Map<Long, UserDocument> userDocMap = getUserDocMap(rows, "id_code");
        Map<Long, DealerSupInfoVO> dealerSupInfoVOMap = getDealerSupInfoMap(rows,"id_code");
        TableAssembler.buildData(table, rows, metaMap.values(), List.of("id_code", "bl_sec_id_code"));
        table.resolveRow(record -> {
            Long secIdCode = CastUtil.castLong(record.get("bl_sec_id_code"));
            Long idCode = CastUtil.castLong(record.get("id_code"));
            UserDocument userDoc = userDocMap.get(idCode);
            String userInfo = "";
            if (userDoc != null) {
                String nickName = new NicknameVO(userDoc.getNickName(), userDoc.getMobile()).toString();
                String userStarLevel = StarLevelEnum.parseByStarLevel(userDoc.getStarLevel()).getDesc();
                userInfo = nickName + " " + userStarLevel + " (" + idCode + ")";
                record.put("userNickname", nickName);
                record.put("userStarLevel", userStarLevel);
                record.put("userIdCode", idCode);
            } else {
                userInfo = idCode + "";
                record.put("userNickname", "-");
                record.put("userStarLevel", "-");
                record.put("userIdCode", idCode);
            }
            ChiefGenSecRelation chiefGenSecRelation = chiefMap.get(secIdCode);
            if (chiefGenSecRelation != null) {
                record.put("departmentName", chiefGenSecRelation.getDepartmentName());
                record.put("chiefName", chiefGenSecRelation.getChiefName());
            }
            record.put("userShowName", userInfo);
            DealerSupInfoVO dealerSupInfoVO = dealerSupInfoVOMap.get(idCode);
            record.put("supInfo", dealerSupInfoVO);
        });
        table.page(total, query.getPageIndex(), query.getPageSize());
        return table;
    }

    private Map<Long, ChiefGenSecRelation> getChiefMap(List<Row> rows, String key) {
        if (CollectionUtils.isEmpty(rows)) {
            return Collections.emptyMap();
        }
        List<UserIdCode> userIdCodeList = rows.stream()
                .map(v -> CastUtil.castLong(v.getValue(key)))
                .filter(v -> v > 0)
                .map(UserIdCode::new)
                .collect(Collectors.toList());
        List<DepartmentId> departmentIdList = Stream.of(filterDepartmentIds.split(","))
                .map(com.tengju.data.domain.shared.CastUtil::castLong)
                .map(DepartmentId::new)
                .collect(Collectors.toList());
        List<ChiefGenSecRelation> chiefGenSecRelationBySecsDepartments = chiefGenSecRelationRepository.getChiefGenSecRelationBySecsDepartments(userIdCodeList, departmentIdList);
        if (CollectionUtils.isEmpty(chiefGenSecRelationBySecsDepartments)) {
            return Collections.emptyMap();
        }
        return chiefGenSecRelationBySecsDepartments.stream()
                .collect(Collectors.toMap(k -> k.getGenSecIdCode().getValue(), v -> v, (v1, v2) -> v1));
    }

    public List<KVVO> overview(ActivityBaseQuery query) {
        Map<String, Meta> metaMap = metaHolder.listMeta("crm_activity_overview");
        CrmActivityAnalysisQO qo = buildQueryDTO(query, metaMap);
        List<Row> rows = crmActivityAnalysisRepository.overview(qo);
        List<KVVO> kvVOs = KVAssembler.buildData(metaMap.values(), rows.get(0));
        return kvVOs;
    }

    public TableVO directorTargetReachTable(ActivityDirectorQuery query) {
        TableVO table = new TableVO();
        Map<String, Meta> metaMap = metaHolder.listMeta("crm_activity_detail_director_table");
        TableAssembler.buildColumns(table, metaMap.values());
        CrmActivityAnalysisQO qo = buildQueryDTO(query, metaMap);
        CompletableFuture<List<Row>> rowCompletableFuture = CompletableFuture.supplyAsync(() -> {
            return crmActivityAnalysisRepository.directorTargetReachTable(qo);
        });
        CompletableFuture<Integer> totalCompletableFuture = CompletableFuture.supplyAsync(() -> {
            return crmActivityAnalysisRepository.countDirectorTargetReachTable(qo);
        });

        List<Row> rows = null;
        int total = 0;
        try {
            rows = rowCompletableFuture.get();
            total = totalCompletableFuture.get();
        } catch (Exception e) {
            log.info("总监达成查询异常！",e);
            throw new RuntimeException("总监达成查询异常！",e);
        }
        TableAssembler.buildData(table, rows, metaMap.values(), List.of("id_code"));
        table.page(total, query.getPageIndex(), query.getPageSize());
        return table;
    }

    public TableVO directorRankTable(ActivityBaseQuery query) {
        TableVO table = new TableVO();
        Map<String, Meta> metaMap = metaHolder.listMeta("crm_activity_rank_director_table");
        TableAssembler.buildColumns(table, metaMap.values());
        CrmActivityAnalysisQO qo = buildQueryDTO(query, metaMap);
        List<Row> rows = crmActivityAnalysisRepository.directorRankTable(qo);
        TableAssembler.buildData(table, rows, metaMap.values(), List.of("chief_id"));
        AtomicInteger rankIndex = new AtomicInteger(0);
        table.resolveRow(record -> {
            record.put("rankIndex", rankIndex.incrementAndGet());
        });
        return table;
    }

    public TableVO overviewTable(ActivityBaseQuery query) {
        TableVO table = new TableVO();
        Map<String, Meta> metaMap = metaHolder.listMeta("crm_activity_overview_table");
        TableAssembler.buildColumns(table, metaMap.values());
        CrmActivityAnalysisQO qo = buildQueryDTO(query, metaMap);
        List<ActivityTarget> targetList = activityRepository.getTargetList(new ActivityId(query.getActivityId()));
        if (!CollectionUtils.isEmpty(targetList)) {
            for (ActivityTarget activityTarget : targetList) {
                //只要有一个正常的品牌，就不是全局视角
                if (activityTarget.getTargetSubjectId() > 0) {
                    qo.setOverallFlag(20);
                    break;
                }
            }
        }
        List<Row> rows = crmActivityAnalysisRepository.overviewTable(qo);
        TableAssembler.buildData(table, rows, metaMap.values());
        return table;
    }

    public List<KVVO> transformFunnel(ActivityBaseQuery query) {
        CrmActivityAnalysisQO qo = buildQueryDTO(query, Collections.emptyMap());
        String metaGroupKey = "crm_activity_transform_funnel";
        if (!ActivityTargetType.SALE.getVal().equals(qo.getActivityType())) {
            metaGroupKey = "crm_activity_pull_transform_funnel";
        }
        Map<String, Meta> metaMap = metaHolder.listMeta(metaGroupKey);
        List<Row> rows = crmActivityAnalysisRepository.transformFunnel(qo);
        Row row = null;
        if (!CollectionUtils.isEmpty(rows)) {
            row = rows.get(0);
        }
        return KVAssembler.buildData(metaMap.values(), row);
    }

    public List<KVVO> activityTransformFunnel(@Valid ActivityBaseQuery query) {
        Map<String, Meta> metaMap = metaHolder.listMeta("crm_activity_overall_transform_funnel");
        CrmActivityAnalysisQO qo = buildQueryDTO(query, metaMap);
        List<Row> rows = crmActivityAnalysisRepository.activityTransformFunnel(qo);
        Row row = null;
        if (!CollectionUtils.isEmpty(rows)) {
            row = rows.get(0);
        }
        return KVAssembler.buildData(metaMap.values(), row);
    }

    public TableVO departmentRankTable(ActivityBaseQuery query) {
        TableVO table = new TableVO();
        Map<String, Meta> metaMap = metaHolder.listMeta("crm_activity_rank_department_table");
        TableAssembler.buildColumns(table, metaMap.values());
        CrmActivityAnalysisQO qo = buildQueryDTO(query, metaMap);
        List<Row> rows = crmActivityAnalysisRepository.departmentRankTable(qo);
        TableAssembler.buildData(table, rows, metaMap.values(), List.of("department_id"));
        return table;
    }

    public TableVO secRankTable(ActivityBaseQuery query) {
        TableVO table = new TableVO();
        Map<String, Meta> metaMap = metaHolder.listMeta("crm_activity_rank_sec_table");
        TableAssembler.buildColumns(table, metaMap.values());
        CrmActivityAnalysisQO qo = buildQueryDTO(query, metaMap);
        List<Row> rows = crmActivityAnalysisRepository.secRankTable(qo);
        Map<Long, UserDocument> userDocMap = getUserDocMap(rows, "id_code");
        TableAssembler.buildData(table, rows, metaMap.values(), List.of("id_code"));
        table.resolveRow(record -> {
            Long idCode = CastUtil.castLong(record.get("id_code"));
            UserDocument userDoc = userDocMap.get(idCode);
            String userInfo = "";
            if (userDoc != null) {
                String nickName = new NicknameVO(userDoc.getNickName(), userDoc.getMobile()).toString();
                String userStarLevel = StarLevelEnum.parseByStarLevel(userDoc.getStarLevel()).getDesc();
                userInfo = nickName + " " + userStarLevel + " (" + idCode + ")";
            } else {
                userInfo = idCode + "";
            }
            record.put("userShowName", userInfo);
        });
        return table;
    }

    public TableVO secTargetReachTable(ActivityTeamQuery query) {
        TableVO table = new TableVO();
        Map<String, Meta> metaMap = metaHolder.listMeta("crm_activity_detail_sec_table");
        TableAssembler.buildColumns(table, metaMap.values());
        CrmActivityAnalysisQO qo = buildQueryDTO(query, metaMap);
//        List<Row> rows = crmActivityAnalysisRepository.secTargetReachTable(qo);
//        int total = crmActivityAnalysisRepository.countSecTargetReachTable(qo);

        CompletableFuture<List<Row>> rowCompletableFuture = CompletableFuture.supplyAsync(() -> {
            return crmActivityAnalysisRepository.secTargetReachTable(qo);
        });
        CompletableFuture<Integer> totalCompletableFuture = CompletableFuture.supplyAsync(() -> {
            return crmActivityAnalysisRepository.countSecTargetReachTable(qo);
        });
        List<Row> rows = null;
        int total = 0;
        try {
            rows = rowCompletableFuture.get();
            total = totalCompletableFuture.get();
        } catch (Exception e) {
            log.info("sec达成查询异常！",e);
            throw new RuntimeException("sec达成查询异常！",e);
        }


        Map<Long, ChiefGenSecRelation> chiefMap = getChiefMap(rows, "id_code");
        Map<Long, UserDocument> userDocMap = getUserDocMap(rows, "id_code");
        TableAssembler.buildData(table, rows, metaMap.values(), List.of("id_code", "bl_sec_id_code"));
        table.resolveRow(record -> {
            Long secIdCode = CastUtil.castLong(record.get("bl_sec_id_code"));
            Long idCode = CastUtil.castLong(record.get("id_code"));
            UserDocument userDoc = userDocMap.get(idCode);
            String userInfo = "";
            if (userDoc != null) {
                String nickName = new NicknameVO(userDoc.getNickName(), userDoc.getMobile()).toString();
                String userStarLevel = StarLevelEnum.parseByStarLevel(userDoc.getStarLevel()).getDesc();
                userInfo = nickName + " " + userStarLevel + " (" + idCode + ")";
                record.put("userNickname", nickName);
                record.put("userStarLevel", userStarLevel);
                record.put("userIdCode", idCode);
            } else {
                userInfo = idCode + "";
                record.put("userNickname", "-");
                record.put("userStarLevel", "-");
                record.put("userIdCode", idCode);
            }
            ChiefGenSecRelation chiefGenSecRelation = chiefMap.get(secIdCode);
            if (chiefGenSecRelation != null) {
                record.put("departmentName", chiefGenSecRelation.getDepartmentName());
                record.put("chiefName", chiefGenSecRelation.getChiefName());
            }
            record.put("userShowName", userInfo);

        });
        table.page(total, query.getPageIndex(), query.getPageSize());
        return table;
    }


    public TableVO serviceProviderTargetReachTable(ActivityTeamQuery query, String activity_target_complete_service_provider_table) {
        TableVO table = new TableVO();
        Map<String, Meta> metaMap = metaHolder.listMeta("crm_activity_detail_service_provider_table");
        TableAssembler.buildColumns(table, metaMap.values());
        CrmActivityAnalysisQO qo = buildQueryDTO(query, metaMap);
//        List<Row> rows = crmActivityAnalysisRepository.serviceProviderTargetReachTable(qo);
//        int total = crmActivityAnalysisRepository.countServiceProviderTargetReachTable(qo);

        CompletableFuture<List<Row>> rowCompletableFuture = CompletableFuture.supplyAsync(() -> {
            return crmActivityAnalysisRepository.serviceProviderTargetReachTable(qo);
        });
        CompletableFuture<Integer> totalCompletableFuture = CompletableFuture.supplyAsync(() -> {
            return crmActivityAnalysisRepository.countServiceProviderTargetReachTable(qo);
        });
        List<Row> rows = null;
        int total = 0;
        try {
            rows = rowCompletableFuture.get();
            total = totalCompletableFuture.get();
        } catch (Exception e) {
            log.info("服务商达成查询异常！",e);
            throw new RuntimeException("服务商达成查询异常！",e);
        }
        Map<Long, ChiefGenSecRelation> chiefMap = getChiefMap(rows, "bl_sec_id_code");
        Map<Long, UserDocument> userDocMap = getUserDocMap(rows, "id_code");
        Map<Long, DealerSupInfoVO> dealerSupInfoVOMap = getDealerSupInfoMap(rows,"id_code");
        TableAssembler.buildData(table, rows, metaMap.values(),List.of("id_code","bl_sec_id_code"));
        table.resolveRow(record -> {
            Long secIdCode = CastUtil.castLong(record.get("bl_sec_id_code"));
            Long idCode = CastUtil.castLong(record.get("id_code"));
            UserDocument userDoc = userDocMap.get(idCode);
            String userInfo = "";
            if (userDoc != null) {
                String nickName = new NicknameVO(userDoc.getNickName(), userDoc.getMobile()).toString();
                String userStarLevel = StarLevelEnum.parseByStarLevel(userDoc.getStarLevel()).getDesc();
                userInfo = nickName + " " + userStarLevel + " (" + idCode + ")";
                record.put("userNickname", nickName);
                record.put("userStarLevel", userStarLevel);
                record.put("userIdCode", idCode);
            } else {
                userInfo = idCode + "";
                record.put("userNickname", "-");
                record.put("userStarLevel", "-");
                record.put("userIdCode", idCode);
            }
            ChiefGenSecRelation chiefGenSecRelation = chiefMap.get(secIdCode);
            if (chiefGenSecRelation != null) {
                record.put("departmentName", chiefGenSecRelation.getDepartmentName());
                record.put("chiefName", chiefGenSecRelation.getChiefName());
            }
            record.put("userShowName", userInfo);
            DealerSupInfoVO dealerSupInfoVO = dealerSupInfoVOMap.get(idCode);
            record.put("supInfo", dealerSupInfoVO);
        });
        table.page(total, query.getPageIndex(), query.getPageSize());
        return table;
    }

    private Map<Long, DealerSupInfoVO> getDealerSupInfoMap(List<Row> rows, String key) {
        if (CollectionUtils.isEmpty(rows)) {
            return Collections.emptyMap();
        }
        List<UserIdCode> userIdCodeList = rows.stream()
                .map(v -> CastUtil.castLong(v.getValue(key)))
                .map(UserIdCode::new)
                .collect(Collectors.toList());
        List<List<UserIdCode>> partitions = com.google.common.collect.Lists.partition(userIdCodeList, 20000);
        Map<Long, DealerSupInfoVO> result = new HashMap<>();
        for (List<UserIdCode> idCodeList : partitions) {
            List<CrmDealerInfo> crmDealerInfos = crmDealerInfoRepository.listCrmDealerInfo(idCodeList);
            if (CollectionUtils.isEmpty(crmDealerInfos)) {
                break;
            }
            for (CrmDealerInfo crmDealerInfo : crmDealerInfos) {
                DealerSupInfoVO supInfoVO = CrmDealerVOAssembler.dealerInfoToSupInfo(crmDealerInfo);
                result.put(crmDealerInfo.getIdCode(),supInfoVO);
            }
        }
        return result;
    }

    private Map<Long, UserDocument> getUserDocMap(List<Row> rows, String key) {
        if (CollectionUtils.isEmpty(rows)) {
            return Collections.emptyMap();
        }
        List<UserIdCode> userIdCodeList = rows.stream()
                .map(v -> CastUtil.castLong(v.getValue(key)))
                .filter(v -> v > 0)
                .map(UserIdCode::new)
                .collect(Collectors.toList());
        List<List<UserIdCode>> partitions = com.google.common.collect.Lists.partition(userIdCodeList, 20000);
        List<UserDocument> result = new ArrayList<>();
        for (List<UserIdCode> partition : partitions) {
            UserSearchForm form = new UserSearchForm();
            form.setIdCodes(partition);
            List<UserDocument> userDocumentList = userDocumentService.batchSearchScroll(form);
            if (CollectionUtils.isEmpty(userDocumentList)) {
                break;
            }
            result.addAll(userDocumentList);
        }
        if (CollectionUtils.isEmpty(result)) {
            return Collections.emptyMap();
        }
        return result.stream()
                .collect(Collectors.toMap(UserDocument::getIdCode, v -> v, (v1, v2) -> v1));
    }

    public TableVO addcartGoodsRankTable(ActivityBaseQuery query) {
        TableVO table = new TableVO();
        Map<String, Meta> metaMap = metaHolder.listMeta("crm_activity_rank_spu_addcart_table");
        TableAssembler.buildColumns(table, metaMap.values());
        CrmActivityAnalysisQO qo = buildQueryDTO(query, metaMap);
        List<Row> rows = crmActivityAnalysisRepository.addcartGoodsRankTable(qo);
        TableAssembler.buildData(table, rows, metaMap.values());
        AtomicInteger rankIndex = new AtomicInteger(0);
        table.resolveRow(record -> {
            record.put("rankIndex", rankIndex.incrementAndGet());
        });
        return table;
    }

    public TableVO moneyoutRankTable(ActivityBaseQuery query) {
        TableVO table = new TableVO();
        Map<String, Meta> metaMap = metaHolder.listMeta("crm_activity_rank_spu_moneyout_table");
        TableAssembler.buildColumns(table, metaMap.values());
        CrmActivityAnalysisQO qo = buildQueryDTO(query, metaMap);
        List<Row> rows = crmActivityAnalysisRepository.moneyoutRankTable(qo);
        TableAssembler.buildData(table, rows, metaMap.values());
        AtomicInteger rankIndex = new AtomicInteger(0);
        table.resolveRow(record -> {
            record.put("rankIndex", rankIndex.incrementAndGet());
        });
        return table;
    }

    public TableVO dealerRankTable(ActivityTeamQuery query) {
        TableVO table = new TableVO();
        Map<String, Meta> metaMap = metaHolder.listMeta("crm_activity_rank_dealer_moneyout_table");
        TableAssembler.buildColumns(table, metaMap.values());
        CrmActivityAnalysisQO qo = buildQueryDTO(query, metaMap);
        List<Row> rows = crmActivityAnalysisRepository.dealerRankTable(qo);
        Map<Long, UserDocument> userDocMap = getUserDocMap(rows, "id_code");
        TableAssembler.buildData(table, rows, metaMap.values(), List.of("id_code"));
        AtomicInteger rankIndex = new AtomicInteger(0);
        table.resolveRow(record -> {
            record.put("rankIndex", rankIndex.incrementAndGet());
            Long idCode = CastUtil.castLong(record.get("id_code"));
            UserDocument userDoc = userDocMap.get(idCode);
            String userInfo = "";
            if (userDoc != null) {
                String nickName = new NicknameVO(userDoc.getNickName(), userDoc.getMobile()).toString();
                String userStarLevel = StarLevelEnum.parseByStarLevel(userDoc.getStarLevel()).getDesc();
                userInfo = nickName + " " + userStarLevel + " (" + idCode + ")";
            } else {
                userInfo = idCode + "";
            }
            record.put("userShowName", userInfo);
        });
        return table;
    }

    private CrmActivityAnalysisQO buildQueryDTO(ActivityBaseQuery query, Map<String, Meta> metaMap) {
        if (query == null) {
            return null;
        }

        Activity activity = activityRepository.getActivityById(new ActivityId(query.getActivityId()));
        //sec、经销商、服务商目标达成参数转换 and 经销商、服务商看板
        if (query instanceof ActivityTeamQuery) {
            UserInfo userInfo = null;
            // 服务商看板或者经销商看板直接通过idCode获取
            if (((ActivityTeamQuery) query).getIdCode() != null) {
                userInfo = remoteUserService.getByIdCode(UserIdCode.of(((ActivityTeamQuery) query).getIdCode()));
            } else {
                userInfo = parseUserQuery(((ActivityTeamQuery) query).getUserQuery());
            }
            UserInfo dominationUserInfo = parseUserQuery(((ActivityTeamQuery) query).getDominationUserQuery());
            String orderKey = ((ActivityTeamQuery) query).getOrderColumn();
            Meta meta = metaMap.get(orderKey);
            return QueryAssembler.assemblerToQuery((ActivityTeamQuery) query, activity, meta, userInfo, dominationUserInfo, query.getUserIdCodeList());
            // 总监目标达成看板
        }
        if (query instanceof ActivityDirectorQuery) {
            String orderKey = ((ActivityDirectorQuery) query).getOrderColumn();
            Meta meta = metaMap.get(orderKey);
            return QueryAssembler.assemblerToQuery((ActivityDirectorQuery) query, activity, meta, filterDepartmentIds, query.getUserIdCodeList());
        }
        return QueryAssembler.assemblerToBaseQuery(query, activity, query.getUserIdCodeList());
    }

    public UserInfo parseUserQuery(String userQuery) {
        if (StringUtils.isBlank(userQuery)) {
            return null;
        }
        UserInfo result = null;
        if (StringUtils.isNotBlank(userQuery)) {
            //判断是不是手机号
            if (MetaUtil.isNumericzidai(userQuery) && userQuery.length() <= 8) {
                long idCode = CastUtil.castLong(userQuery);
                result = remoteUserService.getByIdCode(UserIdCode.of(idCode));
            } else {
                result = remoteUserService.getByWholeMobile(userQuery);
            }
        }
        if (result == null) {
            throw new BizException("用户不存在！idCode:" + userQuery);
        }
        return result;
    }

}
